package com.packtpub.java7.concurrency.chapter6.recipe08.CASABA;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
 * 
 * @author JunJie.Wang
 * 乐观锁的一种实现方式——CAS
 * 
 * 在Java中，AtomicStampedReference<E>也实现了这个作用(用版本戳version来对记录或对象标记，避免并发操作带来的问题)，
 * 它通过包装[E,Integer]的元组来对对象标记版本戳stamp，从而避免ABA问题。
 * 例如下面的代码分别用AtomicInteger和AtomicStampedReference来对初始值为100的原子整型变量进行更新，
 * AtomicInteger会成功执行CAS操作，而加上版本戳的AtomicStampedReference对于ABA问题会执行CAS失败：
 *
 */
public class ABA {

	/**
	 * 乐观的CAS实现
	 */
	private static AtomicInteger atomicInt = new AtomicInteger(100);
	
	/**
	 * CAS实现加上版本号表识
	 */
    private static AtomicStampedReference atomicStampedRef = new AtomicStampedReference(100, 0);
    
	protected static int[] stampHolder = new int [2];

    public static void main(String[] args) throws InterruptedException {
            Thread intT1 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                            atomicInt.compareAndSet(100, 101);
                            System.out.println("AtomicInteger第一步"+Thread.currentThread().getId()+"|||"+atomicInt.get());
                            atomicInt.compareAndSet(101, 100);
                            System.out.println("AtomicInteger第二步"+Thread.currentThread().getId()+"|||"+atomicInt.get());
                    }
            });

            Thread intT2 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                            try {
                                    TimeUnit.SECONDS.sleep(1);
                            } catch (InterruptedException e) {
                            }
                            System.out.println("AtomicInteger第三步"+Thread.currentThread().getId()+"|||"+atomicInt.get());
                            boolean c3 = atomicInt.compareAndSet(100, 101);
                            System.out.println("AtomicInteger第四步"+Thread.currentThread().getId()+"|||"+atomicInt.get()+"结果:"+c3);
                    }
            });

            intT1.start();
            intT2.start();
            intT1.join();
            intT2.join();

            Thread refT1 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                            try {
                                    TimeUnit.SECONDS.sleep(0);
                            } catch (InterruptedException e) {
                            }
                            boolean c1 = atomicStampedRef.compareAndSet(100, 101, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
							System.out.println("AtomicStampedReference线程ID:"+Thread.currentThread().getId()+"|||"+atomicStampedRef.get(stampHolder)+"结果:"+c1);
                            boolean c2 = atomicStampedRef.compareAndSet(101, 100, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
                            System.out.println("AtomicStampedReference线程ID:"+Thread.currentThread().getId()+"|||"+atomicInt.get()+"结果:"+c2);
                    }
            });

            Thread refT2 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                            try {
                                    TimeUnit.SECONDS.sleep(0);
                            } catch (InterruptedException e) {
                            }
                            int stamp = atomicStampedRef.getStamp();
                            System.out.println("AtomicStampedReference线程ID:"+Thread.currentThread().getId()+"|||"+atomicStampedRef.get(stampHolder));
                            boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1);
                            System.out.println("AtomicStampedReference线程ID:"+Thread.currentThread().getId()+"|||"+atomicStampedRef.get(stampHolder));
                            System.out.println(c3); // false
                    }
            });

            refT1.start();
            refT2.start();
    }
}
